//
// Created by wsgalaxy on 3/3/18.
//

#include <gio/gunixinputstream.h>
#include <string.h>
/*
#include "gndinitmodule.h"
#include "gndmodule.h"
#include "gndapp.h"
#include "gndglobal.h"
#include "gndmainwin.h"
*/
#include "gnd.h"

#define MODULE_NAME "GndInitModule"

struct _GndInitModule
{
    GObject parent;
    GndApp * app;
    GSList * list_device;
    GndSession * session;

    char * heart_data;
    gint heart_data_len;

    GMutex * mutex_refresh_device;          //刷新按钮被按下但尚没刷新成功
    GMutex * mutex_device_connecting;       //连接按钮被按下但尚没连接成功

    gint is_connect_succeed;
    //char * str;
};


typedef struct _GndDeviceId
{
    gchar * id;
    gchar * model;
} GndDeviceId;

typedef enum {
    GND_INIT_MODULE_ERROR_NONE,
    GND_INIT_MODULE_ERROR_ADB_EXEC_ERROR
} GndInitModuleError;

typedef enum _GndInitModuleSignal{
    GND_INIT_MODULE_SIGNAL_INIT_FINISH,     //初始化完成的信号
    GND_INIT_MODULE_SIGNAL_REFRESH_DEVICE,  //刷新设备列表的信号
    GND_INIT_MODULE_SIGNAL_CONNECT,
    GND_INIT_MODULE_SIGNAL_DISCONNECT,
    GND_INIT_MODULE_SIGNAL_LAST_SIGNAL
} GndInitModuleSignal;

int gnd_init_module_signal[GND_INIT_MODULE_SIGNAL_LAST_SIGNAL];

void gnd_init_module_interface_init(GndModuleInterface *iface);
void gnd_init_module_start(GndModule * self, gpointer data);            //*虚 启动模块
void gnd_init_module_stop(GndModule * self, gpointer data);             //*虚 停止模块
void gnd_init_module_connect_status(GndModule * self,                   //*虚 模块建立session时返回连接状态
                                    GndSessionStatus status,
                                    gpointer data);

gboolean gnd_init_module_check_adb(GndInitModule * self);               //*异 检查adb状态
void gnd_init_module_adb_error(GndInitModule * self, GndInitModuleError error);     //adb状态异常
gboolean gnd_init_module_adb_check_time_out_cb(GndStdFd * std_fd);      //*回 adb状态检查回调
void gnd_init_module_set_device_list(GndInitModule * module,            //*异 获取设备列表
                                     gpointer data);
gboolean gnd_init_module_set_device_list_cb(GndStdFd * fd);             //*回 adb获取设备列表回调
gboolean gnd_init_module_device_list_clear(GSList ** list);             //清空界面上的设备列表

void gnd_init_module_device_connect(GndInitModule * self,               //*回 连接按钮被按下时回调
                                    GtkButton * button);

gboolean gnd_init_module_adb_port_init(GndInitModule * self, gchar *device_id);     //*弃

void gnd_init_module_ui_set_disconnect(GndInitModule * self);           //设置连接断开UI界面
void gnd_init_module_ui_set_connect(GndInitModule * self);              //设置连接建立UI界面

gboolean gnd_init_module_session_accept_data_cb(GndSessionData * data);     //*回 session接受到数据时的回调
gboolean gnd_init_module_send_heart_data(GndInitModule * self, guint time_out);     //按照延迟发送下一个心跳包


G_DEFINE_TYPE_WITH_CODE(GndInitModule, gnd_init_module, G_TYPE_OBJECT,
    G_IMPLEMENT_INTERFACE(GND_TYPE_MODULE,
                          gnd_init_module_interface_init))

GndInitModule * gnd_init_module_new(gpointer app)
{
    g_return_val_if_fail(GND_IS_APP(app), NULL);

    GndInitModule * module = g_object_new(GND_TYPE_INIT_MODULE, NULL);
    module->app = GND_APP(app);

    return module;
}

void gnd_init_module_class_init(GndInitModuleClass *klass)
{
    gnd_init_module_signal[GND_INIT_MODULE_SIGNAL_INIT_FINISH] = g_signal_new("init-finish",
                                                       GND_TYPE_INIT_MODULE,
                                                       G_SIGNAL_RUN_FIRST,
                                                       0,
                                                       NULL,
                                                       NULL,
                                                       g_cclosure_marshal_VOID__INT,
                                                       G_TYPE_NONE,
                                                       1,
                                                       G_TYPE_INT);
    gnd_init_module_signal[GND_INIT_MODULE_SIGNAL_REFRESH_DEVICE] = g_signal_new("refresh-device",
                                                       GND_TYPE_INIT_MODULE,
                                                       G_SIGNAL_RUN_FIRST,
                                                       0,
                                                       NULL,
                                                       NULL,
                                                       g_cclosure_marshal_VOID__VOID,
                                                       G_TYPE_NONE,
                                                       0);

    gnd_init_module_signal[GND_INIT_MODULE_SIGNAL_CONNECT] = g_signal_new("connect",
                                                       GND_TYPE_INIT_MODULE,
                                                       G_SIGNAL_RUN_FIRST,
                                                       0,
                                                       NULL,
                                                       NULL,
                                                       g_cclosure_marshal_VOID__VOID,
                                                       G_TYPE_NONE,
                                                       0);


    gnd_init_module_signal[GND_INIT_MODULE_SIGNAL_DISCONNECT] = g_signal_new("disconnect",
                                                       GND_TYPE_INIT_MODULE,
                                                       G_SIGNAL_RUN_FIRST,
                                                       0,
                                                       NULL,
                                                       NULL,
                                                       g_cclosure_marshal_VOID__VOID,
                                                       G_TYPE_NONE,
                                                       0);
}

void gnd_init_module_init(GndInitModule *self)
{
    //self->str = "tttttt\n";
    g_signal_connect(self, "refresh-device", G_CALLBACK(gnd_init_module_set_device_list), NULL);
    self->list_device = NULL;
    self->mutex_refresh_device = g_new(GMutex, 1);
    self->mutex_device_connecting = g_new(GMutex, 1);
    self->session = NULL;
    self->is_connect_succeed = 0;

    //生成心跳数据包
    GndMessage * message = gnd_message_new();
    gchar * json_str = "{\"name\":\"gnd_init_module\"}";
    gnd_message_add_raw_data(message, json_str, strlen(json_str));
    self->heart_data_len = gnd_message_generate_bin(message, &(self->heart_data));
    g_assert(self->heart_data_len);
    gnd_message_free(message);
    //session在此创建
    self->session = gnd_session_new(GND_MODULE(self));

    g_mutex_init(self->mutex_refresh_device);
    g_mutex_init(self->mutex_device_connecting);
}

void gnd_init_module_interface_init(GndModuleInterface *iface)
{
    iface->start = gnd_init_module_start;
    iface->stop = gnd_init_module_stop;
    iface->connect_status = gnd_init_module_connect_status;
}

//启动该模块
void gnd_init_module_start(GndModule *self, gpointer data)
{
    //g_print(GND_INIT_MODULE(self)->str);
    g_assert(GND_IS_APP(data));
    GND_INIT_MODULE(self)->app = GND_APP(data);

    //检查adb是否存在
    gnd_init_module_check_adb(GND_INIT_MODULE(self));

    GndMainwin * mainwin = gnd_app_get_mainwin(GND_INIT_MODULE(self)->app);

    g_signal_connect_swapped(mainwin->button_refresh,
                             "clicked",
                             G_CALLBACK(gnd_init_module_set_device_list),
                             self);

    g_signal_connect_swapped(mainwin->button_connect,
                             "clicked",
                             G_CALLBACK(gnd_init_module_device_connect),
                             self);
}

//停止该模块
void gnd_init_module_stop(GndModule *self, gpointer data)
{}

//模块新建session时连接状态
void gnd_init_module_connect_status(GndModule *self, GndSessionStatus status, gpointer data)
{
    GndInitModule * init_module = GND_INIT_MODULE(self);
    if (status == GND_SESSION_STATUS_FAILURE) {
        //g_print("connect failure\n");
        g_message(MODULE_NAME": failure");
        GndConnect * connect = gnd_app_get_connect(init_module->app);
        gnd_connect_stop(connect);
        g_mutex_unlock(GND_INIT_MODULE(self)->mutex_device_connecting);
    } else if (status == GND_SESSION_STATUS_SUCCEED) {
        //g_print("connect succeed\n");
        g_message(MODULE_NAME": connect succeed");
        gnd_session_send_data(init_module->session,
                              init_module->heart_data,
                              init_module->heart_data_len);

        gnd_session_accept_data(init_module->session, 1,
                                (GSourceFunc) gnd_init_module_session_accept_data_cb);
        //gnd_init_module_ui_set_connect(GND_INIT_MODULE(self));
    } else {
        //g_print("connect error\n");
        g_message(MODULE_NAME": connect error");
        g_mutex_unlock(GND_INIT_MODULE(self)->mutex_device_connecting);
    }

    //g_mutex_unlock(GND_INIT_MODULE(self)->mutex_device_connecting);
    return;
}

//检查adb的状态
gboolean gnd_init_module_check_adb(GndInitModule * self)
{
    GndStdFd * std_fd = g_new(GndStdFd, 1);
    std_fd->data = (gpointer) self;
    gchar * adb_path = gnd_app_get_setting_str(self->app, "adb_path");
    gchar * argv[] = {adb_path, "version"};

    if (!g_spawn_async_with_pipes(NULL, argv, NULL,
                                 G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
                                 NULL,
                                 NULL,
                                 &(std_fd->pid),
                                 &(std_fd->std_in),
                                 &(std_fd->std_out),
                                 &(std_fd->std_error),
                                 NULL)) {
        gnd_init_module_adb_error(self, GND_INIT_MODULE_ERROR_ADB_EXEC_ERROR);
        return FALSE;
    }

    GSource * source_time_out = g_timeout_source_new(5000);
    g_source_set_callback(source_time_out,
                          (GSourceFunc) gnd_init_module_adb_check_time_out_cb,
                          (gpointer) std_fd, NULL);
    GSource * source_adb_check = g_child_watch_source_new(std_fd->pid);
    g_source_set_callback(source_adb_check,
                          (GSourceFunc)gnd_do_nothing_return_false,
                          NULL, NULL);
    g_source_add_child_source(source_time_out, source_adb_check);
    g_source_attach(source_time_out, g_main_context_default());

}

//adb检查失败
void gnd_init_module_adb_error(GndInitModule *self, GndInitModuleError error)
{

}

//设置新的adb的值
gboolean gnd_init_module_set_adb()
{}
/*
gboolean gnd_init_module_start_adb_server() {
    gchar * argv_adb_start_server[] = {"/bin/adb",
                                     "start-server"};
    GError * error = NULL;
    GndStdFd _std_fd;
    int spawn_status = g_spawn_async_with_pipes(NULL, argv_adb_start_server, NULL,
                                     G_SPAWN_SEARCH_PATH,
                                     NULL, NULL,
                                     &(_std_fd.pid), &(_std_fd.std_in), &(_std_fd.std_out), &(_std_fd.std_error),
                                     &error);

    if (error) {
        g_print(error->message);
    }
    return TRUE;

}
*/

//adb检查时adb进程结束后回调
gboolean gnd_init_module_adb_check_time_out_cb(GndStdFd *std_fd)
{
    g_spawn_close_pid(std_fd->pid);
    GInputStream * std_in_stream = g_unix_input_stream_new(std_fd->std_out, FALSE);
    gchar buffer_in[BUFFER_SIZE] = {0};
    GndInitModule * self = (GndInitModule *) std_fd->data;
    gssize read_size = g_input_stream_read(std_in_stream,
                                           buffer_in,
                                           BUFFER_SIZE,
                                           NULL, NULL);
    GRegex * regex = g_regex_new("Android Debug Bridge", 0, 0, NULL);

    if (read_size == -1 || read_size == 0 ||
            !regex || !g_regex_match(regex, buffer_in, 0, NULL)) {
        //没检查到adb
        gnd_init_module_adb_error(self, GND_INIT_MODULE_ERROR_ADB_EXEC_ERROR);
        goto finished;
    }
/*
    gchar * argv_adb_start_server[] = {"/bin/adb",
                                     "version"};
    GError * error = NULL;
    GndStdFd _std_fd;
    int spawn_status = g_spawn_async_with_pipes(NULL, argv_adb_start_server, NULL,
                                     G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
                                     NULL, NULL,
                                     &(_std_fd.pid), &(_std_fd.std_in), &(_std_fd.std_out), &(_std_fd.std_error),
                                     &error);

    if (error) {
        g_print(error->message);
    }
*/
    //gnd_init_module_start_adb_server();
    //发出初始化完成的信号
    g_signal_emit(self, gnd_init_module_signal[GND_INIT_MODULE_SIGNAL_INIT_FINISH], 0, GND_INIT_MODULE_INIT_SUCCED);
    //发出刷新设备列表的按钮
    g_signal_emit(self, gnd_init_module_signal[GND_INIT_MODULE_SIGNAL_REFRESH_DEVICE], 0);
    goto finished;

finished:
    g_input_stream_close(std_in_stream, NULL, NULL);
    g_object_unref(std_in_stream);
    g_regex_unref(regex);
    close(std_fd->std_in);
    close(std_fd->std_out);
    close(std_fd->std_error);
    g_free(std_fd);
    return FALSE;
}


//更新设备列表
//在应用刚启动时或者刷新按钮被按下时调用
void gnd_init_module_set_device_list(GndInitModule *module,
                                     gpointer data)
{
    if (!g_mutex_trylock(module->mutex_refresh_device)) {
        return;
    }

    GndStdFd * std_fd = g_new(GndStdFd, 1);
    std_fd->data = (gpointer) module;
    gchar * argv[] = {gnd_app_get_setting_str(module->app, "adb_path"),
                     "devices", "-l", NULL};

    if (!g_spawn_async_with_pipes(NULL, argv, NULL,
                                 G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
                                 NULL, NULL,
                                 &(std_fd->pid),
                                 &(std_fd->std_in), &(std_fd->std_out), &(std_fd->std_error),
                                 NULL)) {
        g_error("adb exec error\n");
    }

    GSource * source_child = g_child_watch_source_new(std_fd->pid);
    GSource * source_time_out = g_timeout_source_new(5000);
    g_source_add_child_source(source_time_out, source_child);
    g_source_set_callback(source_time_out, (GSourceFunc) gnd_init_module_set_device_list_cb,
                          std_fd, NULL);
    g_source_set_callback(source_child, (GSourceFunc) gnd_do_nothing_return_false, NULL, NULL);
    g_source_attach(source_time_out, g_main_context_default());

}

//设备列表更新完毕后回调
gboolean gnd_init_module_set_device_list_cb(GndStdFd *fd)
{
    g_print("set device list\n");

    GInputStream * input_stream = g_unix_input_stream_new(fd->std_out, FALSE);
    gchar buffer[BUFFER_SIZE] = {0};
    gssize read_size = g_input_stream_read(input_stream, buffer, BUFFER_SIZE, NULL, NULL);
    GndInitModule * self = GND_INIT_MODULE(fd->data);
    GndMainwin * mainwin = GND_MAINWIN(gnd_app_get_mainwin(self->app));
    if (read_size == -1 || read_size == 0) {
        g_error("adb error\n");
    }

    gnd_init_module_device_list_clear(&(self->list_device));

    GRegex * regex = g_regex_new("^([^\\s]*).*model:(\\w+)",
                                 G_REGEX_MULTILINE,
                                 0, NULL);
    GMatchInfo * match_info = NULL;

    g_regex_match(regex, buffer, 0, &match_info);

    GndDeviceId * id_each = NULL;

    while (g_match_info_matches(match_info)) {
        id_each = g_new(GndDeviceId, 1);
        id_each->id = g_strdup(g_match_info_fetch(match_info, 1));
        id_each->model = g_strdup(g_match_info_fetch(match_info, 2));
        self->list_device = g_slist_append(self->list_device, (gpointer) id_each);
        g_match_info_next(match_info, NULL);
    }

    gtk_combo_box_text_remove_all(mainwin->combobox_devices);
    gtk_combo_box_text_append(mainwin->combobox_devices,
                             "nodevice",
                              "选择您的设备");

    GSList * tmp_node = self->list_device;
    while (tmp_node) {
        gtk_combo_box_text_append(mainwin->combobox_devices,
                                  ((GndDeviceId *) tmp_node->data)->id,
                                  ((GndDeviceId *) tmp_node->data)->model);
        tmp_node = tmp_node->next;
    }

    gtk_combo_box_set_active_id(GTK_COMBO_BOX(mainwin->combobox_devices), "nodevice");

    g_print(buffer);

    g_mutex_unlock(self->mutex_refresh_device);

    return FALSE;
}

//清除设备列表
gboolean gnd_init_module_device_list_clear(GSList ** list)
{
    GSList * tmp_node = (*list);

    while (tmp_node) {
        GndDeviceId * id = (GndDeviceId *) tmp_node->data;
        g_free(((GndDeviceId *) tmp_node->data)->id);
        g_free(((GndDeviceId *) tmp_node->data)->model);
        g_free(tmp_node->data);
        *list = tmp_node->next;
        //g_free((gpointer) tmp_node);
        g_slice_free(GSList, tmp_node);
        tmp_node = *list;
    }
    *list = NULL;
    return TRUE;
}

//按下连接按钮
void gnd_init_module_device_connect(GndInitModule *self, GtkButton *button)
{

    if (!g_mutex_trylock(self->mutex_device_connecting)) {
        return;
    }

    GndMainwin * mainwin = gnd_app_get_mainwin(self->app);

    const gchar * device_id = gtk_combo_box_get_active_id(GTK_COMBO_BOX(mainwin->combobox_devices));

    GndConnect * connect = gnd_app_get_connect(self->app);

    if (gnd_connect_is_connecting(connect)) {
        gnd_connect_stop(connect);
        g_print("disconnect\n");
        gnd_init_module_ui_set_disconnect(self);
        //gnd_session_close(self->session);
        //gnd_session_free(self->session);
        //self->session = NULL;
        g_mutex_unlock(self->mutex_device_connecting);
        //断开连接
        return;
    }


    if (!g_strcmp0(device_id, "nodevice")) {
        g_warning("no device\n");
        g_mutex_unlock(self->mutex_device_connecting);
        return;
    }

    if (!gnd_connect_set_deviceid(connect, device_id)) {
        g_warning("deviece set failure");
        g_mutex_unlock(self->mutex_device_connecting);
        return;
    }
    //进行连接

    gnd_connect_start(connect);
    //self->session = gnd_session_new(GND_MODULE(self));
    gnd_connect_add_session(connect, self->session);
    g_print("connecting\n");
    return;
}

//初始化adb端口
//已弃用
gboolean gnd_init_module_adb_port_init(GndInitModule *self, gchar * device_id)
{
    char * argv[] = {gnd_app_get_setting_str(self->app, "adb_path"),
                    ""};
}


void gnd_init_module_ui_set_disconnect(GndInitModule *self)
{
    GndMainwin * win = gnd_app_get_mainwin(self->app);
    gtk_button_set_label(win->button_connect, "连接");
    gtk_statusbar_push(win->status_bar,
                       GND_MAINWIN_INFO_ID_CONNECT,
                       "已从设备断开连接");
    self->is_connect_succeed = 0;
    gnd_session_close(self->session);
    g_signal_emit_by_name(self, "disconnect", NULL);

}


void gnd_init_module_ui_set_connect(GndInitModule *self)
{
    GndMainwin * win = gnd_app_get_mainwin(self->app);
    gtk_button_set_label(win->button_connect, "断开连接");
    gtk_statusbar_push(win->status_bar,
                       GND_MAINWIN_INFO_ID_CONNECT,
                       "已连接到设备");
    self->is_connect_succeed = 1;
    g_signal_emit_by_name(self, "connect", NULL);
}




gboolean gnd_init_module_session_accept_data_cb(GndSessionData *data)
{
    g_assert(data);
    GndInitModule * self = GND_INIT_MODULE(data->session->module);
    if (data->status == GND_SESSION_STATUS_FAILURE) {
        //连接失败
        g_message("data accept failure");
        gnd_init_module_ui_set_disconnect(self);
        gnd_connect_stop(data->session->connect);
        goto end;
        //g_mutex_unlock(self->mutex_device_connecting);
    } else {
        //连接成功
        //g_message("data accept succeed");
        //printf("*");
        if (!self->is_connect_succeed) {
            gnd_init_module_ui_set_connect(self);
            g_mutex_unlock(self->mutex_device_connecting);
            //self->is_connect_succeed = 1;
            g_message("set ui connected");
        }
        //gnd_init_module_ui_set_connect(self);
        //g_mutex_unlock(self->mutex_device_connecting);

    }

    //g_mutex_trylock(self->mutex_device_connecting);
    //g_mutex_unlock(self->mutex_device_connecting);

    gnd_init_module_send_heart_data(self, 500);
    //g_print("data accepting\n");

end:
    return FALSE;
}

//*私@gnd_init_module_send_heart_data
gboolean gnd_init_module_send_heart_data_cb(GndInitModule * self)
{
    if (!gnd_connect_is_connecting(self->session->connect))
    {
        return FALSE;
    }
    //发送下一个心跳包
    gnd_session_send_data(self->session,
                          self->heart_data,
                          self->heart_data_len);
    gnd_session_accept_data(self->session, 1,
                            (GSourceFunc) gnd_init_module_session_accept_data_cb);

    //g_print("data accepting\n");
    return FALSE;
}

gboolean gnd_init_module_send_heart_data(GndInitModule *self, guint time_out)
{
    GSource * to_source = g_timeout_source_new(time_out);
    g_source_set_callback(to_source,
                          (GSourceFunc) gnd_init_module_send_heart_data_cb,
                          (gpointer) self,
                          NULL);
    g_source_attach(to_source,
                    gnd_connect_get_main_context(self->session->connect));
    return TRUE;
}
